﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data;
using OSGeo.MapGuide;
using System.Xml;
using System.Web.UI.WebControls;
using Jayrock.Json;

namespace IGIS
{


    /// <summary>
    /// Summary description for FeatPropertyCollection
    /// </summary>
    public class FeatPropertyCollection
    {
        private string IdentityFieldName = "FeatId";
        private SiteUtilities mSiteUtilities;
        private Dictionary<string, FeatProperty> mPropertiesCollection;
        private DataSet mDataSet;
        private MgLayer mLayer;

        public Dictionary<string, FeatProperty> PropertiesCollection
        {
            get { return mPropertiesCollection; }
        }
        public DataSet FeatureDataSet
        {
            get
            {
                mDataSet = GenerateDataSet();
                return mDataSet;
            }
        }

        public string LegendLabel
        {
            get { return mLayer.LegendLabel; }
        }

        public FeatPropertyCollection(SiteUtilities siteUtilities, string layerName, string Filter)
        {
            mSiteUtilities = siteUtilities;
            mLayer = mSiteUtilities.Map.GetLayers().GetItem(layerName) as MgLayer;
            mPropertiesCollection = new Dictionary<string, FeatProperty>();
            GetPropertiesFields();
            GetAdditionalValues();
            FillValues(Filter);

            var sorted = from p in PropertiesCollection
                         orderby p.Value.Alias
                         select p;
            Dictionary<string, FeatProperty> SortedProperties = new Dictionary<string, FeatProperty>();
            foreach (var item in sorted)
            {
                SortedProperties.Add(item.Key, item.Value);
            }
            mPropertiesCollection = SortedProperties;
            mDataSet = GenerateDataSet();
        }
        private void GetPropertiesFields()
        {
            MgByteReader reader = mSiteUtilities.ResourceService.GetResourceContent(mLayer.LayerDefinition);
            string xmlSchema = reader.ToString();
            reader.Dispose();
            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.LoadXml(xmlSchema);
            XmlNodeList xmlProperties = xmlDoc.GetElementsByTagName("PropertyMapping");
            foreach (XmlNode node in xmlProperties)
            {
                string Name = node.SelectSingleNode("Name").InnerText;
                string Alias = node.SelectSingleNode("Value").InnerText;
                PropertiesCollection.Add(Name, new FeatProperty(Name, Alias));
                PropertiesCollection[Name].IsDisplayed = true;
            }
        }
        private void GetAdditionalValues()
        {
            string[] schemaClass = mLayer.FeatureClassName.Split(':');
            MgClassDefinition classDef = mSiteUtilities.FeatureService.GetClassDefinition(new MgResourceIdentifier(mLayer.FeatureSourceId), schemaClass[0], schemaClass[1]);
            MgPropertyDefinitionCollection dpdCollection = classDef.GetProperties();
            for (int i = 0; i < dpdCollection.Count; i++)
            {
                if (dpdCollection[i].PropertyType == MgFeaturePropertyType.DataProperty)
                {
                    MgDataPropertyDefinition dpd = (MgDataPropertyDefinition)dpdCollection[i];
                    if (dpd.Description == "FieldID" || dpd.Description == "מזהה מערכת")
                    {
                        if (!PropertiesCollection.ContainsKey(dpd.Name))
                        {
                            PropertiesCollection.Add(dpd.Name, new FeatProperty(dpd.Name, dpd.Name));
                            PropertiesCollection[dpd.Name].IsDisplayed = false;
                        }
                        PropertiesCollection[dpd.Name].IsReadOnly = true;
                        PropertiesCollection[dpd.Name].IsIdentity = true;
                        IdentityFieldName = dpd.Name;
                    }
                    else if (PropertiesCollection.ContainsKey(dpd.Name))
                    {
                        PropertiesCollection[dpd.Name].IsReadOnly = dpd.ReadOnly;
                    }
                }
            }
        }
        private void FillValues(string Filter)
        {

            MgFeatureQueryOptions queryOptions = new MgFeatureQueryOptions();
            queryOptions.SetFilter(Filter);

            MgFeatureReader reader = mLayer.SelectFeatures(queryOptions);
            reader.ReadNext();
            List<string> ToDelete = new List<string>();

            foreach (var item in PropertiesCollection)
            {
                try
                {
                    int propertyType = reader.GetPropertyType(item.Key);
                    item.Value.PropertyType = propertyType;
                    if (item.Key.ToUpper() == "UID" || item.Key.ToUpper() == "ID" || item.Key == "FeatId")
                    {
                        item.Value.IsReadOnly = true;
                    }
                    if (reader.IsNull(item.Key))
                    {
                        if (propertyType == MgPropertyType.String)
                        {
                            item.Value.Value = string.Empty;
                        }
                        continue;
                    }
                    switch (propertyType)
                    {
                        case MgPropertyType.Boolean:
                            item.Value.LoadValue(reader.GetBoolean(item.Key));
                            break;
                        case MgPropertyType.Byte:
                            item.Value.LoadValue(reader.GetByte(item.Key));
                            break;
                        case MgPropertyType.Double:
                            item.Value.LoadValue(reader.GetDouble(item.Key));
                            break;
                        case MgPropertyType.Int16:
                            item.Value.LoadValue(reader.GetInt16(item.Key));
                            break;
                        case MgPropertyType.Int32:
                            item.Value.LoadValue(reader.GetInt32(item.Key));
                            break;
                        case MgPropertyType.Int64:
                            item.Value.LoadValue(reader.GetInt64(item.Key));
                            break;
                        case MgPropertyType.Single:
                            item.Value.LoadValue(reader.GetSingle(item.Key));
                            break;
                        case MgPropertyType.DateTime:
                            string strDT = "";
                            MgDateTime dt = reader.GetDateTime(item.Key);
                            if (dt != null)
                                strDT = string.Format("{0}/{1}/{2}", dt.Day, dt.Month, dt.Year);
                            item.Value.LoadValue(strDT);
                            break;
                        case MgPropertyType.String:
                            string s = reader.GetString(item.Key);
                            item.Value.LoadValue(reader.GetString(item.Key));
                            if (item.Value.Value.ToString().IndexOf("<a ") >= 0)
                            { ToDelete.Add(item.Key); }
                            break;
                        default:
                            break;
                    }
                }
                catch (MgObjectNotFoundException ex)
                {
                    ToDelete.Add(item.Key);
                }
            }
            foreach (var Key in ToDelete)
            {
                PropertiesCollection.Remove(Key);
            }
            GetAviableValues(reader.ToXml().ToString());
        }
        private void GetAviableValues(string xmlSchema)
        {
            XmlDocument doc = new XmlDocument();
            doc.LoadXml(xmlSchema.ToString());
            XmlNamespaceManager nsmr = new XmlNamespaceManager(doc.NameTable);
            nsmr.AddNamespace("xs", "http://www.w3.org/2001/XMLSchema");

            XmlNodeList elements = doc.GetElementsByTagName("xs:element");

            foreach (XmlNode element in elements)
            {
                XmlNodeList enumeration = element.SelectNodes("xs:simpleType/xs:restriction/xs:enumeration", nsmr);
                if (enumeration.Count > 0)
                {
                    string PropertyName = enumeration[0].ParentNode.ParentNode.ParentNode.Attributes["name"].Value;

                    if (PropertiesCollection.ContainsKey(PropertyName))
                    {
                        PropertiesCollection[PropertyName].AviableValues = new List<string>();
                        foreach (XmlNode node in enumeration)
                        {
                            PropertiesCollection[PropertyName].AviableValues.Add(node.Attributes["value"].Value);
                        }
                    }
                }
            }
        }
        public void FillLookUpValues(string fileName)
        {
            if (string.IsNullOrEmpty(fileName)) return;
            foreach (var p in PropertiesCollection)
            {
                if (p.Key.StartsWith("FK_"))
                {
                    string className = p.Key.Split('_')[1];
               // string className = p.Key;
                    SdfEditor.SdfEditor editor = new SdfEditor.SdfEditor();

                    XmlDocument doc = new XmlDocument();
                    doc.LoadXml(editor.NfcAllEntriesToXml(fileName, className));
                    XmlNodeList nodes = doc.GetElementsByTagName("entry");
                    if (nodes.Count > 0) p.Value.LookUpValues = new Dictionary<int, string>();
                    foreach (XmlNode n in nodes)
                    {
                        int key = int.Parse(n.SelectSingleNode("key").InnerText);
                        string value = n.SelectSingleNode("value").InnerText;
                        p.Value.LookUpValues.Add(key, value);
                    }
                }
            }
        }
        public DataSet GenerateDataSet()
        {
            DataSet dsFeature = new DataSet("dsFeature");
            DataTable dtFeature = new DataTable("dtFeature");
            List<DataColumn> pk = new List<DataColumn>();
            foreach (var property in PropertiesCollection)
            {
                if (property.Value.Value != null && property.Value.Value.ToString().IndexOf("<a ") >= 0)
                { continue; }
                DataColumn dc = new DataColumn(property.Value.Name);
                dc.Caption = property.Value.Alias;
                dc.ReadOnly = property.Value.IsReadOnly;
                dtFeature.Columns.Add(dc);
                if (property.Value.IsIdentity)
                {
                    pk.Add(dc);
                }
            }
            dtFeature.PrimaryKey = pk.ToArray();
            List<object> row = new List<object>();

            DataRow r = dtFeature.NewRow();
            foreach (var property in PropertiesCollection)
            {
                if (property.Value.Value != null && property.Value.Value.ToString().IndexOf("<a ") >= 0)
                { continue; }
                r.SetField<object>(property.Value.Name, property.Value.Value);
            }
            dtFeature.Rows.Add(r);
            dsFeature.Tables.Add(dtFeature);
            return dsFeature;
        }
        public void UpdateFeature(DataSet ds)
        {
            string Filter = string.Empty;
            foreach (var item in PropertiesCollection)
            {
                item.Value.Value = ds.Tables[0].Rows[0].Field<string>(item.Key);
                if (item.Value.IsIdentity)
                {
                    Filter = string.Format("{0}={1}", item.Key, item.Value.Value);
                }
            }
            UpdateFeature(Filter);
        }

        public void UpdateFeature(string Filter)
        {
            MgResourceIdentifier featureResId = new MgResourceIdentifier(mLayer.GetFeatureSourceId());
            MgClassDefinition classDefinition = mSiteUtilities.FeatureService.GetClassDefinition(featureResId, mLayer.FeatureClassName.Split(':')[0], mLayer.FeatureClassName.Split(':')[1]);

            Dictionary<string, Dictionary<string, FeatProperty>> propCollection = new Dictionary<string, Dictionary<string, FeatProperty>>();
            /*
            XmlDocument doc = new XmlDocument();
            doc.LoadXml(mSiteUtilities.FeatureService.DescribeSchemaAsXml(featureResId, mSiteUtilities.FeatureService.GetSchemas(featureResId).GetItem(0)));
        
            XmlNamespaceManager nsmr = new XmlNamespaceManager(doc.NameTable);
            nsmr.AddNamespace("xs", "http://www.w3.org/2001/XMLSchema");
        
            XmlNodeList nodes = doc.SelectNodes("xs:schema/xs:element", nsmr);
            foreach (XmlNode node in nodes)
            {
                string className = node.Attributes["name"].InnerText;
                propCollection.Add(className, new Dictionary<string,FeatProperty>());
                XmlNodeList properties = doc.SelectNodes(String.Format("xs:schema/xs:complexType[@name=\"{0}Type\"]/xs:complexContent/xs:extension/xs:sequence/xs:element", className), nsmr);
                foreach(XmlNode p in properties)
                {
                    if(PropertiesCollection.ContainsKey(p.Attributes["name"].InnerText))
                    {
                        propCollection[className].Add(p.SelectSingleNode("xs:annotation/xs:documentation", nsmr).InnerText, PropertiesCollection[p.Attributes["name"].InnerText]);
                    }
                }
            }
            */
            foreach (var item in classDefinition.GetProperties())
            {
                if (PropertiesCollection.ContainsKey(item.Name))
                {
                    string[] strs = item.QualifiedName.Split('.');
                    if (!propCollection.ContainsKey(strs[0]))
                    {
                        propCollection.Add(strs[0], new Dictionary<string, FeatProperty>());
                    }
                    propCollection[strs[0]].Add(item.QualifiedName.Split('.')[1], PropertiesCollection[item.Name]);
                }
            }

            foreach (var item in propCollection)
            {
                string f = Filter;
                if (item.Value.ContainsKey("UID"))
                {
                    f = "UID=" + item.Value["UID"].Value;
                }
                UpdatingFeature(featureResId, item.Key, f, item.Value);
            }
        }
        /* OldUpdateFeature
        public void oldUpdateFeature(string filter)
        {
            string featureclassname = string.empty;

            mgresourceidentifier featureresid = new mgresourceidentifier(mlayer.getfeaturesourceid());

            mgbytereader reader1 = msiteutilities.resourceservice.getresourceheader(featureresid);
            string s = reader1.tostring();
            //join update
            mgstringcollection r = msiteutilities.featureservice.getclasses(featureresid, mlayer.featureclassname.split(':')[0]);
            if (r.getcount() > 1)
            {
                mgclassdefinition classdefinition = msiteutilities.featureservice.getclassdefinition(featureresid, mlayer.featureclassname.split(':')[0], mlayer.featureclassname.split(':')[1]);
                dictionary<string, list<mgpropertydefinition>> propcollection = new dictionary<string, list<mgpropertydefinition>>();
                foreach(var item in classdefinition.getproperties())
                {
                    string[] strs = item.qualifiedname.split('.');
                    if(!propcollection.containskey(strs[0]))
                    {
                        propcollection.add(strs[0], new list<mgpropertydefinition>());
                    }
                    propcollection[strs[0]].add(item);
                }
                string joinedschema = r.getitem(1);
                string[] arr = joinedschema.split(']');
                string schemaname = arr[2];
                string prefix = arr[1].remove(0, 1);
                string joinname = arr[0].remove(0, 1);
                featureclassname = r.getitem(0);
                dictionary<string, featproperty> parentproperties = new dictionary<string, featproperty>();
                dictionary<string, featproperty> childproperties = new dictionary<string, featproperty>();
                foreach (var item in propertiescollection)
                {
                    if (item.key.indexof(prefix) >= 0)
                    {
                        item.value.name = item.value.name.substring(prefix.length);
                        childproperties.add(item.value.name, item.value);
                    }
                    else
                    {
                        parentproperties.add(item.key, item.value);
                    }
                }

                updatingfeature(featureresid, featureclassname, filter, parentproperties);

                if (propertiescollection.containskey("uid"))
                {
                    mgresourceidentifier childresid = new mgresourceidentifier(featureresid.tostring());
                    string childfeatureclassname = schemaname.split(':')[1];
                    string childupdatingfilter = string.format("uid={0}", propertiescollection["uid"].value);
                    childresid.setname(childfeatureclassname);
                    updatingfeature(childresid, schemaname, childupdatingfilter, childproperties);
                }
                return;
            }
            else
            {
                updatingfeature(featureresid, featureclassname, filter, propertiescollection);
            }
        }
        */
        private void UpdatingFeature(MgResourceIdentifier featureResId, string FeatureClassName, string Filter, Dictionary<string, FeatProperty> propCollection)
        {
            string _filter = "FeatId LIKE '%%'";

            MgFeatureQueryOptions queryOptions = new MgFeatureQueryOptions();
            queryOptions.SetFilter(_filter);

            MgFeatureReader featureReader = mSiteUtilities.FeatureService.SelectFeatures(featureResId, FeatureClassName.Split(':')[1], null);

            featureReader = mSiteUtilities.FeatureService.SelectFeatures(featureResId, FeatureClassName.Split(':')[1], queryOptions);

            featureReader.ReadNext();
            //--------------------------------- 
            //-----lets start update 
            //--------------------------------- 
            MgFeatureCommandCollection updCommands = new MgFeatureCommandCollection();

            MgPropertyCollection properties = new MgPropertyCollection();
            foreach (var item in propCollection)
            {
                try
                {
                    MgProperty prop = item.Value.GenerateProperty();
                    if (prop != null)
                    {
                        prop.Name = item.Key;
                        properties.Add(prop);
                    }
                }
                catch (InvalidOperationException)
                { }
            }

            if (FeatureClassName == string.Empty)
                FeatureClassName = mLayer.FeatureClassName;
            if (properties.Count > 0)
            {
                MgUpdateFeatures updateCommand = new MgUpdateFeatures(FeatureClassName, properties, Filter);
                updCommands.Add(updateCommand);

                MgPropertyCollection res = mSiteUtilities.FeatureService.UpdateFeatures(featureResId, updCommands, false);

                mSiteUtilities.Map.Save(mSiteUtilities.ResourceService);
                //--------------------------------- 
                //-----end of update 
                //--------------------------------- 
                //====================================================================
            }
            featureReader.Close();
        }
    }
}